#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <pthread.h>
#include "can.h"

#define CMD_SET_CAN0_BITRATE     "ip link set can0 type can bitrate 500000 triple-sampling on"
#define CMD_CAN0_UP              "ifconfig can0 up"
#define CMD_CAN0_DOWN            "ifconfig can0 down"

#define CMD_SET_CAN1_BITRATE     "ip link set can1 type can bitrate 500000 triple-sampling on"
#define CMD_CAN1_UP              "ifconfig can1 up"
#define CMD_CAN1_DOWN            "ifconfig can1 down"

/* 设置 can 控制器的函数 */
int can_set_controller(char *can_name)
{
	struct ifreq 		   ifr;		     // 网络接口信息结构体，可以用 ioctrl 来指定 can 设备，主要是通过指定 ifreq 结构体中的 ifr_name 成员
	struct sockaddr_can     can_addr;	  // 用于将套接字和 can 设备进行绑定
	int                     sock_fd = -1; // 用 socket 函数创建 can 的套接字文件，返回文件描述符

	/* 通过参数判断使能 can0 还是 can1

	 * 利用 system 函数执行 shell 命令 
	 * CMD_SET_CAN0_BITRATE 用于设置波特率 
	 * CMD_CAN0_UP 和 CMD_CAN0_DOWN 用于使能和禁用 can 
	 */
	if(strcmp(can_name, "can0") == 0)
	{
		system(CMD_CAN0_DOWN);               
		system(CMD_SET_CAN0_BITRATE);
		system(CMD_CAN0_UP);
	}

	if(strcmp(can_name, "can1") == 0)
	{
		system(CMD_CAN1_DOWN);               
		system(CMD_SET_CAN1_BITRATE);
		system(CMD_CAN1_UP);
	}

	/* 创建套接字文件 */ 
	sock_fd = socket(AF_CAN, SOCK_RAW, CAN_RAW);
	if(sock_fd < 0)
	{
		printf("fail to create socket for %s\n", can_name);
		return -1;
	}

	/* 指定设备为名 can_name 的 can 设备 */
	strcpy(ifr.ifr_name, can_name);

	/* 获取网络接口 */
	ioctl(sock_fd, SIOCGIFINDEX, &ifr); 

	/* 向 can_addr 中填充数据 */
	can_addr.can_family = AF_CAN;
	can_addr.can_ifindex = ifr.ifr_ifindex;

	/* 将套接字与 can0 进行绑定 */
	if(bind(sock_fd, (struct sockaddr *)&can_addr, sizeof(can_addr)) < 0)
	{
		printf("fail to bind %s to socket\n", can_name);
		return -1;
	}

	return sock_fd;
}

int receive_can_message(int can_fd, struct can_frame *rx_frame)
{ 
	int ret = read(can_fd, rx_frame, sizeof(struct can_frame));

	if(ret > 0)
	{
		printf("[recieve data]\n");
		if (rx_frame->can_id & CAN_ERR_FLAG) 
		{
			printf("error frame\n");
		}

		/* 校验帧类型，数据帧还是远程帧 */
		if (rx_frame->can_id & CAN_RTR_FLAG) 
		{
			printf("remote request\n");
		}

		/* 校验帧格式，判断是扩展帧还是标准帧 */
		if (rx_frame->can_id & CAN_EFF_FLAG)	
		{
			printf("extened frame id=0x%08x ", rx_frame->can_id & CAN_EFF_MASK);
		}
		else	
		{
			printf("standard frame id=0x%03x ", rx_frame->can_id & CAN_SFF_MASK);
		}							

		/* 打印信息，用于查看接受的数据 */
		printf("dlc=%d ", rx_frame->can_dlc);
		printf("data=");
		for(int i=0; i<rx_frame->can_dlc; i++)
		{
			printf("0x%02x ", rx_frame->data[i]);
		}
		printf("\n");

		return 0;
	} 
	else
	{
		return ret;
	}
}
